/**
* @file kprintf.c
* Print chars on screen using VGA in compatabile text mode.
*
* Copyrights 2010 Michal Saman, m.saman@designplus.cz.
* This source code is release under the Apache License 2.0.
* http://www.apache.org/licenses/LICENSE-2.0
*/

#include <string.h>
#include <stdarg.h>
#include <stdint.h>
#include <main/kprintf.h>
#include <drivers/vga/vga_text.h>

char tbuf[32];
char bchars[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

/** 
* Convert number to number with different numeric base and output as string.
* @param i Input number to convert
* @param base Numerical base of number
* @param buf Output buffer for returned string.
*
* TODO: support for long long
* TODO: support signed/unsigned integers
*/
void itoa(unsigned i, unsigned base, char *buf) {
	int pos = 0;
	int opos = 0;
	int top = 0;

	if (i==0||base>16) {
		buf[0] = '0';
		buf[1] = '\0';
		return;
	}
	while (i!=0) {
		tbuf[pos] = bchars[i % base];
		pos++;
		i /= base;
	}
	top=pos--;
	for (opos=0; opos<top; pos--,opos++) {
		buf[opos] = tbuf[pos];
	}
	buf[opos] = 0;
}


void itoa_s(int i, unsigned base, char *buf) {
	if (base>16) return;
	if (i<0) {
		*buf++ = '-';
		i *= -1;
	}
	itoa(i, base, buf);
};

/**
* Print formatable string to screen.
* Accepted format parrameters:
* %i for integer number
* %x for hexa number
* %c for character
* @param *str String constant to print, can be formatted.
* @param ... Parameters for formatted string.
*/
int kprintf(const char *str, ...) {
	if (!str)
		return 0;
	va_list	args;
	va_start (args, str);

	size_t i;
	for (i=0; i<strlen(str); i++) {
		switch (str[i]) {
			case '%':
				switch (str[i+1]) {
					/* characters */
					case 'c': {
						char c = va_arg(args, char);
						vga_text_mode_putc(c);
						i++;
						break;
					}
				    /* address of */
					case 's': {
						int c = (int) va_arg(args, int);  // TODO (int &) nefunguje... ??
						char str[max_buffer]={0};
						strcpy(str, (const char*)c);
						vga_text_mode_puts(str);
						i++;
						break;
					}
				    /* integers */
					case 'd':
					case 'i': {
						int c = va_arg(args, int);
						char str[max_buffer]={0};
						itoa(c, 10, str);
						vga_text_mode_puts(str);
						i++;
						break;
					}
					case 'u': {
						unsigned c = va_arg(args, unsigned);
						char str[max_buffer]={0};
						itoa(c, 10, str);
						vga_text_mode_puts(str);
						i++;
						break;
					}
					case 'l': {
						long long c = va_arg(args, long long);
						char str[max_buffer]={0};
						itoa(c, 10, str);
						vga_text_mode_puts(str);
						i++;
						break;
					}
				    /* hex */
					case 'X':
					case 'x': {
						int c = va_arg(args, int);
						char str[max_buffer]={0};
						itoa(c, 16, str);
						vga_text_mode_puts(str);
						i++;
						break;
					}
					default:
						va_end(args);
						return 1;
				}
				break;
			default:
				vga_text_mode_putc(str[i]);
				break;
		}
	}
	va_end(args);
}
